﻿// <copyright file="NtObjectListEntry.cs" company="Sinclair Community College">
// Copyright 2010 Sinclair Community College
// </copyright>
// <originalAuthor>Patrick S. Seymour (patrick.seymour@gmail.com)</originalAuthor>

namespace SinclairCC.AppV
{
    using System;
    using System.Diagnostics.CodeAnalysis;

    /// <summary>
    /// This class represents an entry in the NT Object Exclusion List.
    /// </summary>
    internal class NtObjectListEntry
    {
        /// <summary>
        /// The size of the entry block in total number of bytes.
        /// </summary>
        private int entrySize;

        /// <summary>
        /// The size of the entry block header (i.e., all the data before the object name).
        /// </summary>
        private int entryBlockHeaderSize;

        /// <summary>
        /// The size of the object name in bytes.
        /// </summary>
        private int nameSize;

        /// <summary>
        /// The relative byte offset to the name of the NT Object Manager object
        /// inside entry block.
        /// </summary>
        /// <remarks>
        /// The offset is relative to the beginning of the entry block header.
        /// </remarks>
        private int nameOffset;

        /// <summary>
        /// This field is reserved and is initialized to all zeroes.
        /// </summary>
        [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields", Justification = "This field is marked as reserved in the App-V File Format Specification.")]
        private int reserved;

        /// <summary>
        /// The object's name or partial name.
        /// </summary>
        private string objectName;

        /// <summary>
        /// Initializes a new instance of the NtObjectListEntry class.
        /// </summary>
        /// <param name="dataStream">
        /// A memory stream that contains the raw data for the entry.
        /// </param>
        public NtObjectListEntry(System.IO.MemoryStream dataStream)
        {
            this.objectName = string.Empty;
            this.ReadSection(dataStream);
        }

        /// <summary>
        /// Gets the size of the entry block in total number of bytes.
        /// </summary>
        public int EntrySize
        {
            get { return this.entrySize; }
        }

        /// <summary>
        /// Gets the size of the entry block header (i.e., all the data before the object name).
        /// </summary>
        public int EntryBlockHeaderSize
        {
            get { return this.entryBlockHeaderSize; }
        }

        /// <summary>
        /// Gets the size of the object name in bytes.
        /// </summary>
        public int NameSize
        {
            get { return this.nameSize; }
        }

        /// <summary>
        /// Gets the relative byte offset to the name of the NT Object Manager object
        /// inside entry block.
        /// </summary>
        public int NameOffset
        {
            get { return this.nameOffset; }
        }

        /// <summary>
        /// Gets the object's name or partial name.
        /// </summary>
        public string ObjectName
        {
            get { return this.objectName; }
        }

        /// <summary>
        /// Reads the actual data for this section from the memory stream.
        /// </summary>
        /// <param name="dataStream">
        /// A MemoryStream containing the raw data for the entry.
        /// </param>
        private void ReadSection(System.IO.MemoryStream dataStream)
        {
            System.IO.BinaryReader streamReader = new System.IO.BinaryReader(dataStream);

            this.entrySize = streamReader.ReadInt32();

            // If the entry size is zero, there is no need to read the data for the entry.
            if (this.entrySize > 0)
            {
                this.entryBlockHeaderSize = streamReader.ReadInt32();
                this.nameSize = streamReader.ReadInt32();
                this.nameOffset = streamReader.ReadInt32();
                this.reserved = streamReader.ReadInt32();
                this.objectName = System.Text.Encoding.Unicode.GetString(streamReader.ReadBytes(this.nameSize));
            }
        }
    }
}
